package jinyilw.swing;

import jinyilw.common.DebugTools;
import jinyilw.common.Operator;
import jinyilw.common.file.FileTools;

import java.awt.Component;
import java.awt.Desktop;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;

public class SystemTools
{
	private static Clipboard clipboard;

	private SystemTools()
	{
	}

	public static Clipboard getClipboard()
	{
		if (clipboard == null)
			clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
		return clipboard;
	}

	public static boolean setSysClipboardText(String str)
	{
		if (str == null)
			return false;
		getClipboard().setContents(new StringSelection(str), null);
		return true;
	}

	public static void setSysClipboardImage(Image img)
	{
		if (img == null)
			return;
		getClipboard().setContents(new ImageSelection(img), null);
	}

	public static String getSysClipboardText()
	{
		return (String) getClipboardObject(getClipboard().getContents(null),
				DataFlavor.stringFlavor);
	}

	public static Image getSysClipboardImage()
	{
		return (Image) getClipboardObject(getClipboard().getContents(null),
				DataFlavor.imageFlavor);
	}

	public static Object getClipboardObject(Transferable content,
			DataFlavor flavor)
	{
		if (null != content && content.isDataFlavorSupported(flavor))
		{
			try
			{
				return content.getTransferData(flavor);
			} catch (UnsupportedFlavorException | IOException e)
			{
				e.printStackTrace();
			}
		}
		return null;
	}

	public static void openFile(File file)
	{
		if (file == null || !file.exists())
			return;
		Desktop desktop = Desktop.getDesktop();
		try
		{
			desktop.open(file);
		} catch (IOException e)
		{
			e.printStackTrace();
			try
			{
				desktop.open(file.getParentFile());
			} catch (IOException e1)
			{
				e1.printStackTrace();
			}
		}
	}

	public static void openUserFile(String filePath)
	{
		if (filePath == null)
			return;
		openFile(FileTools.getUserFile(filePath));
	}

	public static void browseURI(URI uri)
	{
		if (uri == null)
			return;
		Desktop desktop = Desktop.getDesktop();
		try
		{
			desktop.browse(uri);
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}

	public static void browseURI(String link)
	{
		URI uri = null;
		try
		{
			uri = new URI(link);
		} catch (URISyntaxException e)
		{
			e.printStackTrace();
		}
		browseURI(uri);
	}

	public static DropTarget makeDropTarget(Component com,
			DropTargetListener listener)
	{
		return new DropTarget(com, listener);
	}

	public static DropTarget makeDropTarget(Component com, Operator<Object> operator)
	{
		return new DropTarget(com, new DefaultDropTargetListener(operator));
	}

	static class DefaultDropTargetListener implements DropTargetListener
	{
		Operator<Object> operator;
		boolean gotData;

		public DefaultDropTargetListener(Operator<Object> operator)
		{
			this.operator = operator;
		}

		private void dropOperatorInThread(Object o)
		{
			new Thread(() -> operator.operate(o)).start();
		}

		@Override
		public void dragEnter(DropTargetDragEvent dtde)
		{
		}

		@Override
		public void dragExit(DropTargetEvent dte)
		{
		}

		@Override
		public void dragOver(DropTargetDragEvent dtde)
		{
		}

		@Override
		public void drop(DropTargetDropEvent dtde)
		{
			dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
			Transferable trans = dtde.getTransferable();
			gotData = false;
			try
			{
				if (trans.isDataFlavorSupported(DataFlavor.imageFlavor))
				{
					if (DebugTools.debug)
						System.out.println("Transfer Image");
					Image img = (Image) trans
							.getTransferData(DataFlavor.imageFlavor);
					if (operator != null)
						dropOperatorInThread(img);
					gotData = true;
				} else if (trans
						.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
				{
					if (DebugTools.debug)
						System.out.println("Transfer FileList");
					Object object = trans
							.getTransferData(DataFlavor.javaFileListFlavor);
					if (operator != null && object instanceof List)
						dropOperatorInThread(object);
					gotData = true;
				}
			} catch (Exception e)
			{
				e.printStackTrace();
			} finally
			{
				dtde.dropComplete(gotData);
			}
		}

		@Override
		public void dropActionChanged(DropTargetDragEvent dtde)
		{
		}
	}

	static class ImageSelection implements Transferable, Serializable
	{
		private static final long serialVersionUID = 1L;
		private final Image image;
		public ImageSelection(Image image)
		{
			this.image = image;
		}

		@Override
		public DataFlavor[] getTransferDataFlavors()
		{
			return new DataFlavor[]{DataFlavor.imageFlavor};
		}

		@Override
		public boolean isDataFlavorSupported(DataFlavor flavor)
		{
			return DataFlavor.imageFlavor.equals(flavor);
		}

		@Override
		public Object getTransferData(DataFlavor flavor)
				throws UnsupportedFlavorException
		{
			if (!DataFlavor.imageFlavor.equals(flavor))
				throw new UnsupportedFlavorException(flavor);
			return image;
		}
	}
}
